package com.maniu.h264maniu;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.util.Log;
import android.view.Surface;
import android.view.View;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

public class H264Player  implements  Runnable {
//    数据源

//    private String path;
    //    解码器
    MediaCodec mediaCodec;
    private final byte[] bytes;
//surface    ffmpeg
    //    显示   目的   surface
//    private Surface surface;
//    public H264Player(String path, Surface surface) {
//        this.path = path;
//        this.surface = surface;
////具体编码名称  h264  h265  vp8 vp9      编码的历史  编码   ITU-T  ISO  名字
////        ISO  的   正规的  mpeg4-avc    h264 编码格式 是有限的
////        初始化
//
//        try {
//            //MediaFormat.MIMETYPE_VIDEO_AVC = "video/avc"
//            mediaCodec = MediaCodec.createDecoderByType("video/avc");
////
//            MediaFormat mediaformat = MediaFormat.createVideoFormat("video/avc",
//                    364, 368);
//            mediaformat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
////            自己的参数  才是 交给dsp
//            mediaCodec.configure(mediaformat, surface, null, 0);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
////        当前支持  硬解H264
//        Log.i("david", "支持: ");
//    }
    public H264Player(byte[] data, Surface surface) {
        this.bytes = data;
//具体编码名称  h264  h265  vp8 vp9      编码的历史  编码   ITU-T  ISO  名字
//        ISO  的   正规的  mpeg4-avc    h264 编码格式 是有限的
//        初始化

        try {
            //MediaFormat.MIMETYPE_VIDEO_AVC = "video/avc"
            mediaCodec = MediaCodec.createDecoderByType("video/avc");
//368x384 可以随便设置
            MediaFormat mediaformat = MediaFormat.createVideoFormat("video/avc",
                    368, 384);
            mediaformat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
//            自己的参数  才是 交给dsp
            mediaCodec.configure(mediaformat, surface, null, 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
//        当前支持  硬解H264
        Log.i("david", "支持: ");
    }

    public void play() {
        mediaCodec.start();
        new Thread(this).start();
    }
    @Override
    public void run() {
//        解码   休息10min
//        这个宽高设置小了会不会有问题，如果解析sps真实数据宽高远远大于设置的宽高

        try {
            decodeH264();
        } catch (Exception e) {
            Log.i("david", "run: "+e.toString());
        }
    }
    private void decodeH264() {
//        byte[] bytes = null;
//        try {
////            bytes 数组里面
//            bytes = getBytes(path);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        int startIndex = 0;
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        while (true) {
            // startIndex不加数字 start==end  start 不会移动
            // startIndex + 1 会和 0x00 0x00 0x01 冲突 还是会 不移动
            // startIndex + 2 比较合适
            // startIndex + n  n越大丢失的像素越多
            int nextFrameStart = findByFrame(bytes, startIndex+2, bytes.length);
            //        ByteBuffer[] byteBuffers= mediaCodec.getInputBuffers();
            int inIndex =  mediaCodec.dequeueInputBuffer(10000);
//            8K
            if (inIndex >= 0  && nextFrameStart != -1) {
                ByteBuffer byteBuffer = mediaCodec.getInputBuffer(inIndex);
//            到底丢多少      文件大小 99M  3M崩了
//            次数 帧来丢   一帧的内容
//                byte
                int length = nextFrameStart - startIndex;
                Log.i("david", "decodeH264: 输入  "+length);
//                丢一部分   数据 到容器 length
                byteBuffer.put(bytes, startIndex, length);
//dsp   bytebuffer   dsp 1        dsp   索引   容器 2
                mediaCodec.queueInputBuffer(inIndex, 0, length, 0, 0);
                startIndex = nextFrameStart;
            }
//            解码了  索引     索引 已经 3秒   dsp  数据 //            8K 是1  不是
//            大于1   等于 小于2
            int outIndex =mediaCodec.dequeueOutputBuffer(info,10000);
            if (outIndex >= 0) {
                //解析帧的速度比较快
                //防止画面放的太快
                try {
                    Thread.sleep(33);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mediaCodec.releaseOutputBuffer(outIndex, true);
            }
        }

    }
    private int findByFrame( byte[] bytes, int start, int totalSize) {
        for (int i = start; i <= totalSize-4; i++) {
            if (((bytes[i] == 0x00) && (bytes[i + 1] == 0x00) && (bytes[i + 2] == 0x00) && (bytes[i + 3] == 0x01))
            ||((bytes[i] == 0x00) && (bytes[i + 1] == 0x00) && (bytes[i + 2] == 0x01))) {
                return i;
            }
        }
        return -1;
    }
    public byte[] getBytes(String path) throws IOException {
        InputStream is = new DataInputStream(new FileInputStream(new File(path)));
        int len;
        int size = 1024;
        byte[] buf;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        buf = new byte[size];
        while ((len = is.read(buf, 0, size)) != -1)
            bos.write(buf, 0, len);
        buf = bos.toByteArray();
        return buf;
    }
}
